#include"mystdio.h"
#include<string.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h>
#include<stdlib.h>

#define TRY_FLUSH 1
#define MUST_FLUSH 2

myFILE* myfopen(const char* pathname,const char* mode)//r,w,a,r+,w+...
{
  if(pathname==NULL)
    return NULL;
  int fd=-1;
  int fg=0;
  if(strcmp(mode,"r")==0)
  {
    fg=O_RDONLY;
    fd=open(pathname,fg);
    if(fd<0)
    {
      perror("open");
      return NULL;
    }
  }
  else if(strcmp(mode,"w")==0)
  {
    fg=O_WRONLY|O_CREAT|O_TRUNC;
    fd=open(pathname,fg,MODE);
    if(fd<0)
    {
      perror("open");
      return NULL;
    }
  }
  else if(strcmp(mode,"a")==0)
  {
    fg=O_WRONLY|O_CREAT|O_APPEND;
    fd=open(pathname,fg,MODE);
    if(fd<0)
    {
      perror("open");
      return NULL;
    }
  }
  else
  {
    //...
    return NULL;
  }
  
  myFILE* fp=(myFILE*)malloc(sizeof(myFILE));
  if(fp==NULL)
  {
    perror("malloc myFILE");
    return NULL;
  }

  fp->fd=fd;
  fp->flags=fg;
  fp->pos=0;
  fp->cap=SIZE;
  fp->flush_mode=LINE_BUFFER;

  return fp;
}

static void myfflushcore(myFILE* fp,int flag)
{
  if(fp->pos==0)
      return;
  if(fp->flush_mode & LINE_BUFFER||flag & MUST_FLUSH)
  {
    if(fp->buffer[fp->pos-1]=='\n'||flag & MUST_FLUSH)
    {
      //将内容从语言级缓冲区拷贝到内核级缓冲区中
      write(fp->fd,fp->buffer,fp->pos);
      fp->pos=0;//清空缓冲区
    }
  }
  else if(fp->flush_mode & FULL_BUFFER)
  {
    if(fp->pos >= 3/4*fp->cap)
    {
      write(fp->fd,fp->buffer,fp->pos);
      fp->pos=0;
    }
  }
  else if(fp->flush_mode & NON_BUFFER)
  {
    write(fp->fd,fp->buffer,fp->pos);
  }
}

void myfflush(myFILE* fp)
{
  myfflushcore(fp,MUST_FLUSH);
}

int myfputs(const char* str,myFILE* fp)
{
  if(strlen(str)==0)
    return 0;

  //缺少超容量检查与扩容
  //...
  //-----------------
  
  //向文件流里写，本质是：拷贝 -> 文件缓冲区
  memcpy(fp->buffer+fp->pos,str,sizeof(char)*strlen(str));
  fp->pos+=strlen(str);

  //如果条件满足，则自行刷新缓冲区
  myfflushcore(fp,TRY_FLUSH);
  return strlen(str);
}

void myfclose(myFILE* fp)
{
  //强制刷新语言级缓冲区到内核
  myfflush(fp);

  //强制将内容从内核缓冲区刷新到磁盘（不是必须的）
  fsync(fp->fd);

  //关闭文件
  close(fp->fd);

  //释放文件结构体指针
  free(fp);
  fp=NULL;
}




